#include"Sock.hpp"
#include<sys/epoll.h>
void Usage(std::string proc)
{
  cout <<"Usage\n\t" <<proc <<" port" << endl;
  exit(1);
}
#define NUM 128
int main(int argc,char* argv[])
{
  if(argc != 2)
  {
    Usage(argv[0]);
  }
  uint16_t port = atoi(argv[1]);
  int listen_sock = Sock::Socket(); 
  Sock::Bind(listen_sock,port);
  Sock::Listen(listen_sock);
    
  int epoll_fd = epoll_create(128);
  struct epoll_event efds[NUM]; //用于保存epoll_wait获取的就绪的事件&fd
  struct epoll_event rfd;
  rfd.data.fd = listen_sock;
  rfd.events = EPOLLIN;
  epoll_ctl(epoll_fd,EPOLL_CTL_ADD,listen_sock,&rfd); //注册关于监听套接字的事件
  for(;;)
  {
    int n = epoll_wait(epoll_fd,efds,NUM,-1); 
    switch(n)
    {
      case 0:
        cout <<"timeout 超时！" << endl;
        break;
        cerr <<"epoll_wait err" << endl;
      case -1:
        break;
      default:
        for(int i = 0;i<n;i++)
        {
          //已经就绪的fd及其对应的事件都保存在efds数组当中
          if(efds[i].events & EPOLLIN) //读事件就绪 ->与客户端建立链接的套接字上读取事件就绪 || 监听套接字上的读事件就绪
          {
            if(efds[i].data.fd == listen_sock ) 
            {
                int new_fd = Sock::Accept(listen_sock);
                cout <<"监听套接字上有读取事件就绪！！！new_sock:" << new_fd  << endl;
                struct epoll_event nrfd; 
                nrfd.data.fd = new_fd;
                nrfd.events = EPOLLIN;
                epoll_ctl(epoll_fd,EPOLL_CTL_ADD,new_fd,&nrfd);
            }
            else if(efds[i].events & EPOLLIN) //与客户端建立链接的套接字上读取事件就绪
            {
              cout <<"sock:" << efds[i].data.fd <<" 有读取事件就绪！！！" << endl;
              char buf[1024];
              ssize_t n = read(efds[i].data.fd,buf,sizeof(buf)-1);
              if(n > 0)
              {
                buf[n] = '\0';
                cout <<"sock:" <<efds[i].data.fd << "  client# "<<buf << endl;
              }
              else if(n == 0)
              {
                cout << "sock:" << efds[i].data.fd << " client quit!! done:close & EPOLL_CTL_DEL" << endl;
                //注意：close文件描述符的同时，还要将当前fd从epoll模型当中移除
                close(efds[i].data.fd);
                epoll_ctl(epoll_fd,EPOLL_CTL_DEL,efds[i].data.fd,&efds[i]);
              }
              else 
              {
                cout <<"sock:" <<  efds[i].data.fd <<" read fail!  done:close & EPOLL_CTL_DEL" << endl;
                //注意：close文件描述符的同时，还要将当前fd从epoll模型当中移除
                close(efds[i].data.fd);
                epoll_ctl(epoll_fd,EPOLL_CTL_DEL,efds[i].data.fd,&efds[i]);
              }
            }
          }
          else if(efds[i].events & EPOLLOUT) //写事件就绪
          {
            //....
          }
          else //异常事件就绪
          {
            //...
          }
        }
        break;
    }
  }
  close(epoll_fd);
  close(listen_sock);
  return 0;
}
